package com.hl.annotation.bean_init_01;

import com.hl.annotation.bean_init_01.service.UserService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * 测试依赖注入
 * Bean对象和Java对象的区别
 * Bean对象的创建过程
 *      UserService -> 推断构造方法 -> 普通Java对象 ->            【Bean的实例化，得到普通对象】
 *      依赖注入(根据注解或其他机制填充属性值) ->                   【依赖注入，填充属性】
 *      初始化(执行某个特殊方法，实现了接口InitializingBean) ->     【Bean的初始化，执行方法】
 *      初始化后(执行AOP, 得到代理对象，如果不执行则没有代理对象) ->  【初始化后，执行AOP，得到代理对象】
 *      放入单利池 Map<key为BeanName，value为Bean对象> ->         【初始化的普通对象/代理对象 放入单利池Map，实现单例Bean】
 *
 * 依赖注入时的查找策略：按优先级 byType -> byName（使用构造器和使用Set方法是一样的）
 *
 * @author liuhuan
 */
public class Test {

    public static void main(String[] args) {
        // 启动一个 spring 容器，加载配置类AppConfig，扫描配置的路径
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

        // Bean 对象，里面的属性有值，spring 容器创建时，会依赖注入相关属性
        // 创建过程：UserService -> 推断构造方法 -> 普通Java对象 ->            【Bean的实例化，得到普通对象】
        //          依赖注入(根据注解或其他机制填充属性值) ->                   【依赖注入，填充属性】
        //          初始化(执行某个特殊方法，实现了接口InitializingBean) ->     【Bean的初始化，执行方法】
        //          初始化后(执行AOP, 得到代理对象，如果不执行则没有代理对象) ->  【初始化后，执行AOP，得到代理对象】
        //          放入单利池 Map<key为BeanName，value为Bean对象> ->         【初始化的普通对象/代理对象 放入单利池Map，实现单例Bean】
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.test();

        // Java 对象，里面的属性没值
//        UserService userService1 = new UserService();
//        userService1.test();

        // spring 容器创建的 Bean 对象，默认都是 单例Bean，即 .getBean() 获取的是同一个对象
        // 实现原理，使用 Map<key为BeanName，value为Bean对象>
        // 单例Bean 和 单例模式 不是一样的。单例模式
        //      单例模式：同一个类，只能有一个 实例对象
        //      单例Bean：用同个一名字，只能获取一个 实例对象。换一个名字就是一个新的对象
        UserService userService21 = applicationContext.getBean("userService", UserService.class);
        UserService userService22 = applicationContext.getBean("userService", UserService.class);
        System.out.println("---- 单例Bean ----");
        System.out.println("userService21 = " + userService21);
        System.out.println("userService22 = " + userService22);

    }
}
